//
//  HMAudioTool.m
//  01-音效播放
//
//  Created by apple on 14/11/7.
//  Copyright (c) 2014年 heima. All rights reserved.
//

#import "KCAudioTool.h"
#import <AVFoundation/AVFoundation.h>
#import "KCCategory.h"
#import "VoiceConverter.h"

static NSString *KCAudioDirectoryName = @"com.KCAudio.Audio";

@interface KCAudioTool()<AVAudioPlayerDelegate>

@property (nonatomic, strong) NSMutableDictionary *soundIDs;
@property (nonatomic, strong) NSMutableDictionary *players;

@property (nonatomic, copy) void(^playFinishHandle)();
@property (nonatomic, copy) NSString *currentPlayFileName;


@end

@implementation KCAudioTool


+ (instancetype)shareAudioTool
{
    static id instance_ = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance_ = [[self alloc] init];
    });
    return instance_;
}

+ (void)initialize
{
    // 1.创建音频会话
    AVAudioSession *session = [AVAudioSession sharedInstance];
    // 2.设置会话类型
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    // 3.激活会话
    [session setActive:YES error:nil];
    
    NSString *audioPath = KCAudioDirectoryName.kc_cachePath;
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    if (![fileManager fileExistsAtPath:audioPath]) {
        
        [fileManager createDirectoryAtPath:audioPath withIntermediateDirectories:NO attributes:nil error:nil];
    }
    
}

- (NSMutableDictionary *)soundIDs
{
    if (!_soundIDs) {
        _soundIDs = [NSMutableDictionary dictionary];
    }
    return _soundIDs;
}
- (NSMutableDictionary *)players
{
    if (!_players) {
        _players = [NSMutableDictionary dictionary];
    }
    return _players;
}

- (void)playSoundWithFilename:(NSString *)filename
{

    //初始化播放器的时候如下设置
    UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
    AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
                            sizeof(sessionCategory),
                            &sessionCategory);
    
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
                             sizeof (audioRouteOverride),
                             &audioRouteOverride);
    
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    [audioSession setActive:YES error:nil];
    // 0.判断文件名是否为nil
    if (filename == nil) {
        return;
    }
    
    // 1.从字典中取出音效ID
    SystemSoundID soundID = [self.soundIDs[filename] unsignedIntValue];
    
    // 判断音效ID是否为nil
    if (!soundID) {
        KCLog(@"创建新的soundID");
        
        // 音效ID为nil
        // 根据文件名称加载音效URL
        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
        
        // 判断url是否为nil
        if (!url) {
            return;
        }
        
        // 创建音效ID
        AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
        
        // 将音效ID添加到字典中
        [self soundIDs][filename] = @(soundID);
    }
    // 播放音效
    AudioServicesPlaySystemSound(soundID);
}

- (void)disposeSoundWithFilename:(NSString *)filename
{
    // 0.判断文件名是否为nil
    if (filename == nil) {
        return;
    }
    
    // 1.从字典中取出音效ID
    SystemSoundID soundID = [[self soundIDs][filename] unsignedIntValue];
    
    if (soundID) {
        // 2.销毁音效ID
        AudioServicesDisposeSystemSoundID(soundID);
        
        // 3.从字典中移除已经销毁的音效ID
        [[self soundIDs] removeObjectForKey:filename];
    }
  
}

// 根据音乐文件名称播放音乐
- (AVAudioPlayer *)playAudioWithFilename:(NSString  *)filename
{
    // 0.判断文件名是否为nil
    if (filename == nil) {
        return nil;
    }
    //初始化播放器的时候如下设置
    UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
    AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
                            sizeof(sessionCategory),
                            &sessionCategory);
    
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
                             sizeof (audioRouteOverride),
                             &audioRouteOverride);
    
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    [audioSession setActive:YES error:nil];
    
    
    // 1.从字典中取出播放器
    AVAudioPlayer *player = [self players][filename];
    
    // 2.判断播放器是否为nil
    if (!player) {
        KCLog(@"创建新的播放器");
        
        // 2.1根据文件名称加载音效URL
//        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
        NSURL *url = [NSURL fileURLWithPath:filename];
        // 2.2判断url是否为nil
        if (!url) {
            return nil;
        }
        
        // 2.3创建播放器
        NSError *error = nil;
        player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
        KCLog(@"%@", error);
        
        player.delegate = self;
        // 2.4准备播放
        if(![player prepareToPlay])
        {
            
            return nil;
        }
        // 允许快进
//        player.enableRate = YES;
//        player.rate = 3;
        
        // 2.5将播放器添加到字典中
        [self players][filename] = player;
        
    }
    // 3.播放音乐
    if (!player.playing)
    {
        [player play];
        [self setProximityMonitoringEnabled:YES];
        self.currentPlayFileName = filename;
    }
   
    return player;
}

// 根据音乐文件名称暂停音乐
- (void)pauseAudioWithFilename:(NSString  *)filename
{
    // 0.判断文件名是否为nil
    if (filename == nil) {
        return;
    }
    
    // 1.从字典中取出播放器
    AVAudioPlayer *player = [self players][filename];

    // 2.判断播放器是否存在
    if(player)
    {
        // 2.1判断是否正在播放
        if (player.playing)
        {
            // 暂停
            [player pause];
        }
    }
    
}

// 根据音乐文件名称停止音乐
- (void)stopAudioWithFilename:(NSString  *)filename
{
    // 0.判断文件名是否为nil
    if (filename == nil) {
        return;
    }
    
    // 1.从字典中取出播放器
    AVAudioPlayer *player = [self players][filename];

    // 2.判断播放器是否为nil
    if (player) {
        // 2.1停止播放
        [player stop];
        // 2.2清空播放器
//        player = nil;
        // 2.3从字典中移除播放器
        [[self players] removeObjectForKey:filename];
        
        [self setProximityMonitoringEnabled:NO];
        
        self.currentPlayFileName = nil;
    }
}


// 根据音乐文件名称播放音乐
- (void)playAudioWithUrlStr:(NSString *)urlStr playFinishHandle:(void (^)())playFinishHandle
{
    [self stopAudioWithFilename:self.currentPlayFileName];
    
    NSString *audioPath = [self audioPathWithUrlStr:urlStr];
    
    
    !self.playFinishHandle ? : self.playFinishHandle();
    
    self.playFinishHandle = playFinishHandle;
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:audioPath]) {
        
        [self playAudioWithFilename:audioPath];
        
    }else {
        
        [self downloadAndCacheaudioWithUrlStr:urlStr completion:^() {
            
            [self playAudioWithFilename:audioPath];
            
            
        }];
        
    }
    
}


// 根据音乐url称暂停音乐
- (void)pauseAudioWithUrlStr:(NSString  *)urlStr
{
    [self pauseAudioWithFilename:[self audioPathWithUrlStr:urlStr]];
}

// 根据音乐url停止音乐
- (void)stopAudioWithUrlStr:(NSString  *)urlStr
{
    [self stopAudioWithFilename:[self audioPathWithUrlStr:urlStr]];
    
    self.currentPlayFileName = nil;
}


- (void)downloadAndCacheaudioWithUrlStr:(NSString *)urlStr completion:(void(^)())completion
{
    NSURLSession *session = [NSURLSession sharedSession];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlStr] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        KCLog(@"%@", [NSThread currentThread]);
        
        if (error) {
            KCLog(@"下载失败");
            return ;
        }
        
        NSString *audioPath = [self audioPathWithUrlStr:urlStr];
        
        NSString *amrAudioPath = [audioPath stringByReplacingOccurrencesOfString:@".wav" withString:@".amr"];
        
        [data writeToFile:amrAudioPath atomically:YES];
        
        NSInteger result = [VoiceConverter ConvertAmrToWav:amrAudioPath wavSavePath:audioPath];
        
        if (result) {
            NSFileManager *mgr = [NSFileManager defaultManager];
            [mgr removeItemAtPath:amrAudioPath error:nil];
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
           
            !completion ? : completion();
        });
        
    }];
    
    [dataTask resume];
    
    
}


- (void)stopAllAudio
{
    // 1.从字典中取出播放器
    
    [self.players enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, AVAudioPlayer  *_Nonnull player, BOOL * _Nonnull stop) {
        [player stop];
    }];
    
    [self.players removeAllObjects];
    
    if (self.playFinishHandle) {
        self.playFinishHandle = nil;
        [self setProximityMonitoringEnabled:NO];
    }
    self.currentPlayFileName = nil;
    
    
}

- (NSString *)audioPathWithUrlStr:(NSString *)urlStr
{
    return [NSString stringWithFormat:@"%@/%@.wav", KCAudioDirectoryName,urlStr.kc_MD5String].kc_cachePath;
}

#pragma mark -AVAudioPlayerDelegate

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    !self.playFinishHandle ? : self.playFinishHandle();
    
    self.playFinishHandle = nil;
    
    [self setProximityMonitoringEnabled:NO];
    
    self.currentPlayFileName = nil;
}

#pragma mark -听筒or扬声器
- (void)setProximityMonitoringEnabled:(BOOL)enable
{
    [[UIDevice currentDevice] setProximityMonitoringEnabled:enable]; //建议在播放之前设置yes，播放结束设置NO，这个功能是开启红外感应
    
    if(enable)//添加监听
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(proximityStateDidChange) name:UIDeviceProximityStateDidChangeNotification
                                                   object:nil];
    else//移除监听
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceProximityStateDidChangeNotification object:nil];
}

- (void)proximityStateDidChange
{
    //如果此时手机靠近面部放在耳朵旁，那么声音将通过听筒输出，并将屏幕变暗（省电啊）
    if ([[UIDevice currentDevice] proximityState] == YES)
    {
        
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    }
    else
    {
        
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    }
}


@end
